package com.hzgj.soa.protocol.pb.message;

import com.hzgj.bcl.soa.api.IdempotentIdGen;
import com.hzgj.bcl.soa.rpc.RpcContext;
import com.hzgj.bcl.soa.rpc.client.RequestOptions;
import com.hzgj.bcl.soa.rpc.message.Message;
import com.hzgj.bcl.soa.spi.MessageHandleFactory;
import com.hzgj.bcl.soa.util.Constants;
import com.hzgj.bcl.util.lang.StrKit;
import com.hzgj.soa.protocol.pb.data.RequestMessage;
import com.hzgj.soa.protocol.pb.data.ResponseMessage;
import com.hzgj.soa.protocol.pb.data.SimpleValue;
import com.hzgj.soa.protocol.pb.encode.SimpleEncoder;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import static com.hzgj.soa.protocol.pb.handler.PbConstants.PB_PROTOCOL;

/**
 * Created by warning on 2016/11/4.
 */
public class PbMessageHandleFactory implements MessageHandleFactory {
    @Override
    public Message buildRequestMessage(Method method, Object[] args, RequestOptions options) {
        RequestMessage requestMessage = new RequestMessage();
        requestMessage.service = options.getReferenceDef().getService();
        requestMessage.method = method.getName();
        requestMessage.contextId = RpcContext.getContextId();
        if (StrKit.isBlank(RpcContext.getWhoIm())) {
            requestMessage.clientName = options.getSource();
        } else {
            requestMessage.clientName = RpcContext.getWhoIm();
        }
        if (args != null && args.length > 0) {
            requestMessage.parameters = new ArrayList<>(args.length);
            for (Object arg : args) {
                SimpleValue value = SimpleEncoder.encode(arg);
                requestMessage.parameters.add(value);
            }
        }
        if (options.getMethodDef() != null) {
            IdempotentIdGen idempotentIdGen = options.getMethodDef().getIdempotentIdGen();
            if (idempotentIdGen != null) {
                String continueId = idempotentIdGen.getContinueId();
                if (StrKit.isBlank(continueId)) {
                    throw new RuntimeException("idempotentIdGen exist,but continueId is null");
                } else {
                    requestMessage.bizId = continueId;
                }
            }
        }
        Message message = new Message(requestMessage);
        message.putHeader(Constants.MESSAGE_HEADER_SERIALIZATION_NAME, PB_PROTOCOL);
        return message;
    }

    @Override
    public Message buildResponse(Long req_id, Object reply, boolean is_exception) {
        ResponseMessage responseMessage;
        if (is_exception) {
            responseMessage = ResponseMessage.failed((Throwable) reply);
        } else {
            responseMessage = ResponseMessage.success(reply);
        }
        responseMessage.messageId = req_id;
        Message message = new Message(responseMessage);
        message.putHeader(Constants.MESSAGE_HEADER_SERIALIZATION_NAME, PB_PROTOCOL);
        return message;
    }

    @Override
    public Message buildErrorResponse(Throwable throwable, Map<String, Object> headers) {
        ResponseMessage responseMessage;
        responseMessage = ResponseMessage.failed(throwable);
        Message message = new Message(responseMessage);
        message.putHeader(Constants.MESSAGE_HEADER_SERIALIZATION_NAME, PB_PROTOCOL);
        message.putHeaders(headers);
        return message;
    }

    @Override
    public <T> T handleResponse(Object response) throws Exception {
        ResponseMessage responseMessage = (ResponseMessage) response;
        if (responseMessage.success) {
            try {
                return (T) SimpleEncoder.decode(responseMessage.result.dataType, responseMessage.result.data, Object.class);
            } catch (Exception e) {
                throw new ExecutionException(e);
            }
        } else {
            return (T) new Exception(responseMessage.errorInfo);
        }
    }


    @Override
    public String getName() {
        return PB_PROTOCOL;
    }
}
